/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package game.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.*;
import java.sql.*;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.print.DocFlavor;

/**
 *
 * @author RERIR
 */
public class TestGameServer implements IGameServer{
    private static TestGameServer srv = null;
    private Connection con;
    private PreparedStatement list;
    private PreparedStatement newGame;
    private PreparedStatement updateGame;
    private PreparedStatement deleteGame;
    private PreparedStatement fixMove;
    private DatagramSocket socket;
    private DatagramPacket packet;
    private byte[] buffer;
    private ServerSocket serverSocket;
    private Socket[] clients;
    private ObjectInputStream[] in;
    private ObjectOutputStream[] out;

    public TestGameServer(String url) throws SQLException, SocketException, IOException {
        String[] sUrl = url.split(","); 
/*        con = DriverManager.getConnection(sUrl[0], sUrl[1], sUrl[2]);
        
        list = con.prepareStatement("SELECT * FROM Gamers WHERE Gamer2 IS NULL",
                ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        newGame = con.prepareStatement("INSERT INTO GAMES (game_id) VALUES (?)");
        updateGame = con.prepareStatement("UPDATE Gamers SET gamer2 = ? WHERE id = ?");
        fixMove = con.prepareStatement("UPDATE Games SET moves = ? WHERE game_id = ?");
        deleteGame = con.prepareStatement("DELETE FROM Games WHERE game_id = ?"); */
        
        buffer = new byte[BUFFER_SIZE];
        socket = new DatagramSocket(SERVER_PORT);
        packet = new DatagramPacket(buffer, buffer.length);
        serverSocket = new ServerSocket(IGameServer.SERVER_TCP_PORT);
        clients = new Socket[2];
        in = new ObjectInputStream[2];
        out = new ObjectOutputStream[2];
        
    }

    

    @Override
    public int connect(Gamer g) throws GameException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Gamer[] getList() {
        Gamer[] tmp = null;
        
        try {
            ResultSet rs = list.executeQuery();
            rs.last();
            tmp = new Gamer[rs.getRow()];
            do {
//                tmp[rs.getRow()-1] = new Gamer(rs.getString(2), new Socket(rs.getString(3), rs.getInt(4)));
                tmp[rs.getRow()-1] = new Gamer(rs.getString(2), null);
                tmp[rs.getRow()-1].setGameId(rs.getInt(1));
            } while (rs.previous());
        } catch (SQLException sQLException) {
            System.out.println("Error #1: " + sQLException.getMessage());
        }
        return tmp;
    }
    
    public Gamer[] getList(int n) {
        Gamer[] tmp = {new Gamer("test", null), new Gamer("aaaa", null), new Gamer("bbbb", null)};
        return tmp;
    }

    @Override
    public int startGame(int id) {

        Object obj;
        int[] moves = new int[game.client.GameField.SIZE_FIELD*game.client.GameField.SIZE_FIELD];
        System.out.println("TCP game start.  1: " + clients[0].getRemoteSocketAddress() + " 2: " + clients[1].getRemoteSocketAddress());
        while(true) {
            try {
                obj = in[0].readObject();
                out[1].writeObject(obj);
                System.out.println("TCP send 1->2: " + obj);
                if (endGame(IGameServer.PLUS, moves, obj)) break;
                obj = in[1].readObject();
                out[0].writeObject(obj);
                System.out.println("TCP send 2->1: " + obj);                
                if (endGame(IGameServer.ZERO, moves, obj)) break;
            } catch (IOException ex) {
                    System.out.println("Err IO: " + ex.getMessage());
                    break;
            } catch (ClassNotFoundException ex) {
                    System.out.println("Err CastObject: " + ex.getMessage());
            }
        }
        return 0;
        
    }
    @Override
    public Integer newGame(String g) {
        Integer id = new Random().nextInt();
        //TODO newGame
        return g.equals("") ? 0 : id;
    }
    

    @Override
    public boolean disconnect(int id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String joinGame(String g, String id) {
        String str = "test";
        //TODO joingame
        return str;
    }

    @Override
    public boolean move(Gamer g, int pos) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean stopGame(Gamer g) {
        //TODO stop game code here
        for( int i=0; i < clients.length; i++) {
            try {
                in[i].close();
                out[i].close();
                clients[i].close();
            } catch (IOException ex) {
                System.out.println("Err IO: " + ex.getMessage());
                return false;
            }
        }
        return true;
    }
    
    public static void main(String[] args) {
        
        try {
             srv = new TestGameServer("jdbc:derby://localhost:1527/test,admin,admin");
        } catch (SQLException ex) {
            System.out.println("Err SQL: " + ex.getMessage());
        } catch (SocketException ex) {
            System.out.println("Err Socket: " + ex.getMessage());
        } catch (IOException ex) {
            System.out.println("Err IO: " + ex.getMessage());
        }
        if (srv == null) System.exit(1);
        new Thread(new Runnable() {

            @Override
            public void run() {
                srv.runUDP(1000);
            }
        }).start();
        srv.runTCP();
        srv.startGame(0);
    }
/**
 * Run UDP server
 * @param n - count of cycles
 */
    private void runUDP(int n) {
        while (n-- > 0) {
            processQuery();
        }
    }
/**
 * Run TCP server
 * @param s - dummy parameters
 */
    private void runTCP() {
        Socket tmp;
        int i = 0;
        while (true) {
            try {
                tmp = serverSocket.accept();
                System.out.println("TCP new connection " + tmp.getRemoteSocketAddress() + " N=" + i);
                clients[i] = tmp;
                in[i] = new ObjectInputStream(tmp.getInputStream());
                out[i] = new ObjectOutputStream(tmp.getOutputStream());
                i++;
                if (i > clients.length-1) break;
            } catch (IOException ex) {
                System.out.println("Err TCP_SRV: " + ex.getMessage());
            }
        }
    }

    private void processQuery() {
        clearPacket();
        try {
            socket.receive(packet);
            String query = new String(packet.getData(), packet.getOffset() , packet.getLength());
            SocketAddress sender = packet.getSocketAddress();
            Object obj = null;
            System.out.println("UDP Query: " + query);
            String[] as = query.split("[\b]+");
            switch(as[0]) {
                case "list":
                    obj = getList(1); //TODO remove stub getList
                    break;
                case "new":
                    if (as.length == 2) obj = newGame(as[1]);
                    break;
                case "join":
                    if (as.length == 3) obj = joinGame(as[1], as[2]);
                    break;
            }
            if (obj == null) obj = "Error #123";
            
            System.out.println("UDP Answer: " + obj);
             
            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
            ObjectOutputStream oOut = new ObjectOutputStream(bOut);
            oOut.writeObject(obj);
            oOut.close();
            packet.setData(bOut.toByteArray());
            packet.setSocketAddress(sender);
            socket.send(packet);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    private void clearPacket() {
        buffer = new byte[BUFFER_SIZE];
        packet.setData(buffer);
    }

    private boolean endGame(int side, int[] moves, Object obj) {
        
        if (obj instanceof Integer) {
            moves[(Integer)obj] = side;
            if (java.util.Arrays.asList(moves).contains(0)) return false; //TODO check end game
        }
        
        return true;

    }
    
}
